/**
 * 
 */
package com.workable.assignment.services.ws;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.workable.assignment.Constants;
import com.workable.assignment.annotations.Loggable;
import com.workable.assignment.annotations.MovieRamaExceptionHandler;
import com.workable.assignment.domain.Movie;
import com.workable.assignment.domain.rottentomatoes.RTMovie;
import com.workable.assignment.domain.rottentomatoes.RTMovieActor;
import com.workable.assignment.domain.rottentomatoes.RTMovieReviews;
import com.workable.assignment.domain.themoviedb.TMDBMovie;
import com.workable.assignment.domain.themoviedb.TMDBMovieDetails;
import com.workable.assignment.domain.themoviedb.TMDBMovieReviews;
import com.workable.assignment.services.api.IMovieRamaApiService;
import com.workable.assignment.services.ws.factories.MovieRamaResponseFactory;

/**
 * RESTfull Web Service MovieRamaService
 * 
 * @author npapadopoulos
 * 
 */
@Service(Constants.SERVICE_NAME)
public class MovieRamaService implements IMovieRamaService {

    @Autowired
    private IMovieRamaApiService apiService;

    /**
     * Service method for searching movies based on the query string.
     * 
     * @throws UnsupportedEncodingException
     */
    @Override
    @GET
    @Path(Constants.SERVICE_SEARCH_MOVIES_PATH)
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
    @Loggable
    @MovieRamaExceptionHandler
    public Response search(@QueryParam("query") String query) throws UnsupportedEncodingException {
        List<RTMovie> rtMovieSearchResult = apiService.getSearchedRTMovies(query);
        List<TMDBMovie> tmdbMovieSearchResult = apiService.getSearchedTMDBMovies(query);

        Map<String, Movie> movies = new HashMap<String, Movie>();

        if (rtMovieSearchResult != null) {
            for (RTMovie rtMovie : rtMovieSearchResult) {
                Movie movie = new Movie();
                movie.setTitle(rtMovie.getTitle());
                movie.setDescription(rtMovie.getSynopsis());

                RTMovieReviews rtMovieReviews = apiService.getRTMovieReviews(rtMovie.getId());

                movie.setNumberOfReviews(rtMovieReviews != null ? rtMovieReviews.getTotal() : 0);
                List<String> actors = new ArrayList<>();
                for (RTMovieActor rtActor : rtMovie.getAbridgedCast()) {
                    actors.add(rtActor.getName());
                }
                movie.setStarringActors(actors);

                String year = String.valueOf(rtMovie.getYear());
                if (String.valueOf(rtMovie.getYear()).length() > 4) {
                    year = String.valueOf(rtMovie.getYear()).split("-")[0];
                }
                movie.setYearOfProduction(year);
                movies.put(rtMovie.getTitle().toLowerCase().trim(), movie);
            }
        }
        if (tmdbMovieSearchResult != null) {
            for (TMDBMovie tmdbMovie : tmdbMovieSearchResult) {
                TMDBMovieDetails tmdbMovieDetails = apiService.getTMDBMovieDetails(tmdbMovie.getId());
                TMDBMovieReviews tmdbMovieReviews = apiService.getTMDBMovieReviews(tmdbMovie.getId());

                Movie existing = movies.get(tmdbMovie.getTitle().toLowerCase().trim());
                if (existing != null) {
                    if (existing.getDescription() == null) {
                        existing.setDescription(tmdbMovieDetails != null ? tmdbMovieDetails.getOverview() : "");
                    } else if (tmdbMovieDetails != null && tmdbMovieDetails.getOverview() != null) {
                        existing.setDescription(tmdbMovieDetails.getOverview().length() > existing.getDescription()
                            .length() ? tmdbMovieDetails.getOverview() : existing.getDescription());
                    }
                    if (tmdbMovieReviews != null) {
                        Integer rev = existing.getNumberOfReviews();
                        existing.setNumberOfReviews(rev + tmdbMovieReviews.getTotalResults());
                    }
                } else {
                    Movie tmdb = new Movie();
                    tmdb.setTitle(tmdbMovie.getTitle());
                    tmdb.setDescription(tmdbMovieDetails != null ? tmdbMovieDetails.getOverview() : "");
                    tmdb.setNumberOfReviews(tmdbMovieReviews != null && tmdbMovieReviews.getResults() != null ? tmdbMovieReviews
                        .getResults().size() : 0);

                    String year = tmdbMovie.getReleaseDate();
                    if (tmdbMovie.getReleaseDate().length() > 4) {
                        year = tmdbMovie.getReleaseDate().split("-")[0];
                    }
                    tmdb.setYearOfProduction(year);
                    movies.put(tmdbMovie.getTitle().toLowerCase().trim(), tmdb);
                }
            }
        }

        return MovieRamaResponseFactory.createResponse(movies.values(), Constants.STATUS_OK,
            Constants.STATUS_OK_MESSAGE);
    }

    /**
     * Service method for getting the movies which are currently in the theaters.
     * 
     */
    @Override
    @GET
    @Path(Constants.SERVICE_NOW_PLAYING_MOVIES_PATH)
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
    @Loggable
    @MovieRamaExceptionHandler
    public Response playing() throws UnsupportedEncodingException {
        List<RTMovie> rtMovieSearchResult = apiService.getRTMoviesInTheater();
        List<TMDBMovie> tmdbMovieSearchResult = apiService.getTMDBMoviesInTheater();

        Map<String, Movie> movies = new HashMap<String, Movie>();

        if (rtMovieSearchResult != null) {
            for (RTMovie rtMovie : rtMovieSearchResult) {
                Movie movie = new Movie();
                movie.setTitle(rtMovie.getTitle());
                movie.setDescription(rtMovie.getSynopsis());

                RTMovieReviews rtMovieReviews = apiService.getRTMovieReviews(rtMovie.getId());

                movie.setNumberOfReviews(rtMovieReviews != null ? rtMovieReviews.getTotal() : 0);
                List<String> actors = new ArrayList<>();
                for (RTMovieActor rtActor : rtMovie.getAbridgedCast()) {
                    actors.add(rtActor.getName());
                }
                movie.setStarringActors(actors);

                String year = String.valueOf(rtMovie.getYear());
                if (String.valueOf(rtMovie.getYear()).length() > 4) {
                    year = String.valueOf(rtMovie.getYear()).split("-")[0];
                }
                movie.setYearOfProduction(year);
                movies.put(rtMovie.getTitle().toLowerCase().trim(), movie);
            }
        }
        if (tmdbMovieSearchResult != null) {
            for (TMDBMovie tmdbMovie : tmdbMovieSearchResult) {
                TMDBMovieDetails tmdbMovieDetails = apiService.getTMDBMovieDetails(tmdbMovie.getId());
                TMDBMovieReviews tmdbMovieReviews = apiService.getTMDBMovieReviews(tmdbMovie.getId());

                Movie existing = movies.get(tmdbMovie.getTitle().toLowerCase().trim());
                if (existing != null) {
                    if (existing.getDescription() == null) {
                        existing.setDescription(tmdbMovieDetails != null ? tmdbMovieDetails.getOverview() : "");
                    } else if (tmdbMovieDetails != null && tmdbMovieDetails.getOverview() != null) {
                        existing.setDescription(tmdbMovieDetails.getOverview().length() > existing.getDescription()
                            .length() ? tmdbMovieDetails.getOverview() : existing.getDescription());
                    }
                    if (tmdbMovieReviews != null) {
                        Integer rev = existing.getNumberOfReviews();
                        existing.setNumberOfReviews(rev + tmdbMovieReviews.getTotalResults());
                    }
                } else {
                    Movie tmdb = new Movie();
                    tmdb.setTitle(tmdbMovie.getTitle());
                    tmdb.setDescription(tmdbMovieDetails != null ? tmdbMovieDetails.getOverview() : "");
                    tmdb.setNumberOfReviews(tmdbMovieReviews != null && tmdbMovieReviews.getResults() != null ? tmdbMovieReviews
                        .getResults().size() : 0);
                    
                    String year = tmdbMovie.getReleaseDate();
                    if (tmdbMovie.getReleaseDate().length() > 4) {
                        year = tmdbMovie.getReleaseDate().split("-")[0];
                    }
                    tmdb.setYearOfProduction(year);
                    movies.put(tmdbMovie.getTitle().toLowerCase().trim(), tmdb);
                }
            }
        }

        return MovieRamaResponseFactory.createResponse(movies.values(), Constants.STATUS_OK,
            Constants.STATUS_OK_MESSAGE);
    }
}
